package com.metal.meta.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.metal.meta.service.FormService;
import com.metal.meta.service.form.FormDataService;
import com.metal.meta.util.ResponseUtil;
import com.metal.meta.util.ThreadLocalUtil;
import com.metal.meta.exception.ResponseCode;
import com.metal.meta.exception.ResponseVo;
import com.metal.silver.domain.CustomerMarket;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.*;

/**
 * @ClassName FormController
 * @Description
 * @Author liukun
 * @Date 2022/9/8 10:44
 */
@Slf4j
@Controller
public class FormController {

    @RequestMapping("/form/tree")
    @ResponseBody
    public ResponseVo<JSONObject> queryFormTree(@RequestBody JSONObject queryJsonObject) {

        JSONObject rootNode = FormService.levelFill(queryJsonObject);

        return ResponseUtil.buildVoByResponseCode(ResponseCode.CODE_SUCCESS, rootNode);

    }

    @RequestMapping("/form/update")
    @ResponseBody
    public ResponseVo<JSONObject> addFormConfigs(@RequestBody JSONObject updateJsonObject) {
        try {
            // add 的时候，为每个要增加的内容加一个 uuid 字段，随机唯一即可。
            String formName = updateJsonObject.getString("form");
            if (updateJsonObject.containsKey("add") && updateJsonObject.getJSONArray("add") != null) {
                JSONArray addJsonArray = updateJsonObject.getJSONArray("add");
                // 此方法内部会检查：不允许同一个form中有相同的column_name
                FormService.addFormConfig(updateJsonObject, addJsonArray);
            }
            if (updateJsonObject.containsKey("update") && updateJsonObject.getJSONArray("update") != null) {
                JSONArray updateJsonArray = updateJsonObject.getJSONArray("update");
                FormService.updateFormConfig(updateJsonArray);
            }
            if (updateJsonObject.containsKey("delete") && updateJsonObject.getJSONArray("delete") != null) {
                JSONArray deleteJsonArray = updateJsonObject.getJSONArray("delete");
                FormService.deleteFormConfig(deleteJsonArray);
            }

            ThreadLocalUtil.remove();

            JSONObject formQueryJson = new JSONObject();
            formQueryJson.put("form", formName);
            JSONObject rootNode = FormService.levelFill(formQueryJson);

            return ResponseUtil.buildVoByResponseCode(ResponseCode.CODE_SUCCESS, rootNode);
        } catch (Exception e) {
            log.error("执行元数据配置CRUD出错", e);
            if (e.toString().contains("E11000 duplicate key error collection")) {
                return ResponseUtil.buildVoByResponseCode(ResponseCode.DUPLICATE_KEY_ERROR, ThreadLocalUtil.get("adding"));
            }
        }
        return ResponseUtil.buildVoByResponseCode(ResponseCode.CODE_ERROR);
    }

    @PostMapping("/form/importFormExcel")
    @ResponseBody
    public ResponseVo importExcel(@RequestParam("file") MultipartFile excel) throws Exception {
        ExcelReader reader = ExcelUtil.getReader(excel.getInputStream());
        List<LinkedHashMap> configList = reader.readAll(LinkedHashMap.class);
        // 从入参解析，如果有uuid，那么进行更新操作；没有uuid，进行新增操作。
        Boolean handleResult = FormService.handleExcelLines(configList);
        if (handleResult == true) {
            return ResponseUtil.buildVoByResponseCode(ResponseCode.CODE_SUCCESS);
        }
        return ResponseUtil.buildVoByResponseCode(ResponseCode.CODE_ERROR, "保存excel数据失败");
    }

    /**
     * 样例：
     * http://localhost:8080/form/exportExcel?namespace=开发&system=商城管理系统&system_module=crm&form=客户
     *
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping("/form/exportExcel")
    @ResponseBody
    public void exportConfigure(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String fileName = new String(("form_config").getBytes(), "utf-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");

        String params = "namespace,system,system_module,form";
        JSONObject queryJson = new JSONObject();
        Arrays.stream(params.split(",")).forEach(item -> {
            queryJson.put(item, request.getParameter(item));
        });

        List<JSONObject> jsonObjList = FormService.loadFormConfig(queryJson);
        ArrayList<Map<String, Object>> rows = CollUtil.newArrayList();
        jsonObjList.stream().forEach(item -> {
            Map map = JSONObject.toJavaObject(item, Map.class);
            rows.add(map);
        });
        //通过工具类创建writer
        ExcelWriter writer = ExcelUtil.getWriter(true);
        //一次性写出所有内容，默认样式
        writer.write(rows);

        // 写出到输出流
        ServletOutputStream out = response.getOutputStream();
        writer.flush(out, true);

        // 关闭writer，释放内存
        writer.close();
        //关闭输出流
        IoUtil.close(out);

    }

    /**
     * 通过读取mongodb表单配置信息，生成mysql建表语句，为后面的生成页面UI做准备。
     * @param queryJsonObject
     * @return
     */
    @RequestMapping("/form/2tableSql")
    @ResponseBody
    public ResponseVo<String> toTableSql(@RequestBody JSONObject queryJsonObject) {

        List<JSONObject> configJsonObjList = FormService.loadFormConfig(queryJsonObject);
        String sql = FormService.makeTableSqlByConfig(queryJsonObject, configJsonObjList);

        return ResponseUtil.buildVoByResponseCode(ResponseCode.CODE_SUCCESS, sql);

    }

    /**
     * 接口提交json格式数据，进行保存
     * @param jsonObject
     * @return
     */
    @RequestMapping("/form/json/save")
    @ResponseBody
    public ResponseVo saveJson2Collection(@RequestBody JSONObject jsonObject) {
        FormDataService.saveJson2Collection(jsonObject.getString("collection"), jsonObject.getJSONObject("data"));
        return ResponseUtil.buildVoByResponseCode(ResponseCode.CODE_SUCCESS);
    }

    @RequestMapping("/form/json/update")
    @ResponseBody
    public ResponseVo jsonUpdate(@RequestBody JSONObject inputJsonObject) {

        // 这里要说明一下，可能存在多个form的数据共同放在一个collection中的场景，所以collection和form是有区别的。
        // 这里是用来提取数据找到数据要更新的mongodb collection
        String collection = inputJsonObject.getString("collection");
        String uuid = inputJsonObject.getString("uuid");

        // 更新操作，默认增加一个update_time字段，用来记录数据本次的更新时间
        inputJsonObject.put("update_time", DateUtil.now());

        // 构造form的坐标coordinate，以便查找对应的配置来完成更新操作
        JSONObject formCoordinate = new JSONObject();
        formCoordinate.put("system", inputJsonObject.getString("system"));
        formCoordinate.put("form", inputJsonObject.getString("form"));

        FormDataService.jsonUpdate(collection, uuid, inputJsonObject.getJSONObject("data"), formCoordinate);
        return null;
    }

    @RequestMapping("/form/json/query")
    @ResponseBody
    public ResponseVo jsonQuery(@RequestBody JSONObject inputJsonObject) {
        String collection = inputJsonObject.getString("collection");
        List<JSONObject> resultList = FormDataService.jsonQuery(collection, inputJsonObject.getJSONObject("query"));
        return ResponseUtil.buildVoByResponseCode(ResponseCode.CODE_SUCCESS, resultList);
    }

    @RequestMapping("/form/show")
    public String edit(ModelMap mmap)
    {
        String tree = "{\"success\":true,\"code\":100000,\"msg\":\"处理成功\",\"data\":{\"del_flag\":0,\"column_name\":\"customer\",\"form_father\":\"customer\",\"sort\":0,\"type\":\"form\",\"column_desc\":\"客户营销表单\",\"uuid\":\"5bd6cee9-3b59-483e-98c9-25e8147e9c27\",\"system_module\":\"crm\",\"update_time\":\"2022-10-20 11:11:15\",\"system\":\"商城管理系统\",\"children_unique\":[\"uuid\"],\"form\":\"customer_market\",\"children\":[{\"del_flag\":0,\"column_name\":\"uuid\",\"form_father\":\"customer\",\"sort\":1,\"type\":\"text\",\"column_desc\":\"客户编号\",\"uuid\":\"d6057c84-1072-4cdb-8bc2-7850fc85248c\",\"system_module\":\"crm\",\"update_time\":\"2022-10-20 11:11:16\",\"system\":\"商城管理系统\",\"form\":\"customer_market\",\"parent_column_name\":\"customer\",\"namespace\":\"开发\",\"add_time\":\"2022-10-20 11:11:16\"},{\"del_flag\":0,\"column_name\":\"name\",\"form_father\":\"customer\",\"sort\":2,\"type\":\"text\",\"column_desc\":\"姓名\",\"uuid\":\"5af02031-6e21-413e-bc3b-0491a86795a0\",\"system_module\":\"crm\",\"update_time\":\"2022-10-20 11:11:16\",\"system\":\"商城管理系统\",\"form\":\"customer_market\",\"parent_column_name\":\"customer\",\"namespace\":\"开发\",\"add_time\":\"2022-10-20 11:11:16\"},{\"del_flag\":0,\"column_name\":\"gender\",\"form_father\":\"customer\",\"sort\":3,\"type\":\"text\",\"column_desc\":\"性别\",\"uuid\":\"381f82ed-9d74-402a-8039-fa2c93cff715\",\"system_module\":\"crm\",\"update_time\":\"2022-10-20 11:11:16\",\"system\":\"商城管理系统\",\"form\":\"customer_market\",\"parent_column_name\":\"customer\",\"namespace\":\"开发\",\"add_time\":\"2022-10-20 11:11:16\"},{\"del_flag\":0,\"column_name\":\"age\",\"form_father\":\"customer\",\"sort\":4,\"type\":\"int\",\"column_desc\":\"年龄\",\"uuid\":\"9fa4d677-7c2d-404f-b3ea-66e4e8d60b3c\",\"system_module\":\"crm\",\"update_time\":\"2022-10-20 11:11:16\",\"system\":\"商城管理系统\",\"form\":\"customer_market\",\"parent_column_name\":\"customer\",\"namespace\":\"开发\",\"add_time\":\"2022-10-20 11:11:16\"},{\"del_flag\":0,\"column_name\":\"spouse_name\",\"form_father\":\"customer\",\"sort\":5,\"type\":\"text\",\"column_desc\":\"配偶姓名\",\"uuid\":\"a98d173c-0f57-4145-a568-ee0268bb8c73\",\"system_module\":\"crm\",\"update_time\":\"2022-10-20 11:11:16\",\"system\":\"商城管理系统\",\"form\":\"customer_market\",\"parent_column_name\":\"customer\",\"namespace\":\"开发\",\"add_time\":\"2022-10-20 11:11:16\"},{\"del_flag\":0,\"column_name\":\"spouse_age\",\"form_father\":\"customer\",\"sort\":6,\"type\":\"int\",\"column_desc\":\"配偶年龄\",\"uuid\":\"144f3f75-ea4c-456a-ad8f-0982538deb63\",\"system_module\":\"crm\",\"update_time\":\"2022-10-20 11:11:16\",\"system\":\"商城管理系统\",\"form\":\"customer_market\",\"parent_column_name\":\"customer\",\"namespace\":\"开发\",\"add_time\":\"2022-10-20 11:11:16\"},{\"del_flag\":0,\"column_name\":\"mobile\",\"form_father\":\"customer\",\"sort\":7,\"type\":\"text\",\"column_desc\":\"联系电话\",\"uuid\":\"0d7cdb9a-abcc-42a2-8869-b683aaa79d32\",\"system_module\":\"crm\",\"update_time\":\"2022-10-20 11:11:16\",\"system\":\"商城管理系统\",\"form\":\"customer_market\",\"parent_column_name\":\"customer\",\"namespace\":\"开发\",\"add_time\":\"2022-10-20 11:11:16\"},{\"del_flag\":0,\"column_name\":\"address\",\"form_father\":\"customer\",\"sort\":8,\"type\":\"text\",\"column_desc\":\"住址\",\"uuid\":\"4c17528b-41e3-4c77-8182-445d6c163ed7\",\"system_module\":\"crm\",\"update_time\":\"2022-10-20 11:11:16\",\"system\":\"商城管理系统\",\"form\":\"customer_market\",\"parent_column_name\":\"customer\",\"namespace\":\"开发\",\"add_time\":\"2022-10-20 11:11:16\"},{\"del_flag\":0,\"column_name\":\"document_type\",\"choose\":[\"身份证号\",\"统一社会信用代码\"],\"form_father\":\"customer\",\"sort\":9,\"type\":\"select\",\"column_desc\":\"证件类型\",\"uuid\":\"912de8f2-1774-453d-bb62-e05e28dcf363\",\"system_module\":\"crm\",\"update_time\":\"2022-10-20 11:11:16\",\"system\":\"商城管理系统\",\"form\":\"customer_market\",\"parent_column_name\":\"customer\",\"namespace\":\"开发\",\"add_time\":\"2022-10-20 11:11:16\"}],\"parent_column_name\":\"\",\"namespace\":\"开发\",\"add_time\":\"2022-10-20 11:11:15\"}}";
        mmap.put("tree", JSONObject.parse(tree));
        return "silver/form/index";
    }

    public static void main(String[] args) {

        File excel = new File("/Users/kelvin/Documents/1-work/10-临时存放/表单.xlsx");
        ExcelReader reader = ExcelUtil.getReader(excel);
        List<LinkedHashMap> configList = reader.readAll(LinkedHashMap.class);
        Boolean handleResult = FormService.handleExcelLines(configList);
        log.info("获取文件成功");
    }
}
